from . import builders
from .node import Node, mark_changed, depth_sort, scan_all


MODE_BUILD = 1
MODE_FORCE = 2
MODE_CLEAN = 3


def load_builders():
    """loads all global builders"""
    for name in dir(builders):
        mod = getattr(builders, name)
        if hasattr(mod, "register_builder"):
            mod.register_builder()


def load_project(projfilename):
    """loads a gabot project, returning a nodelist"""
    root = Node.new(projfilename)
    scan_all(root)
    return depth_sort(root)


def build(nodelist, force = False):
    """builds the given nodelist"""
    if force:
        loginfo("BUILD", "rebuilding the entire project")
    else:
        if mark_changed(nodelist) == 0:
            loginfo("BUILD", "project is up to date")
            return []
        loginfo("BUILD", "rebuilding changed files")
    
    errors = []
    results = {}
    for level in nodelist:
        results.clear()
        for node in level:
            if not force and not node.rebuild:
                node.retrieve_cache()
            else:
                res = node.build()
                if res is not None:
                    results[node] = res
        
        for node, res in results.iteritems():
            res.wait()
            if res.warnings:
                print res.warnings
            if res.errors:
                print res.errors
            if res.failed:
                errors.append(res)
            else:
                node.store_cache()
        
        if errors:
            break
    
    if errors:
        loginfo("BUILD", "project has failed to build, %d errors", len(errors))
    else:
        loginfo("BUILD", "project has been built successfully")
    return errors


def clean(nodelist):
    """cleans the project tree from build outputs"""
    for level in nodelist:
        for node in level:
            node.clean()
    loginfo("CLEAN", "project has been cleaned")


def process(projfilename, mode = MODE_BUILD):
    """processes a project (all-in-one)"""
    load_builders()
    nodelist = load_project(projfilename)
    if mode == MODE_BUILD:
        build(nodelist, force = False)
    elif mode == MODE_FORCE:
        build(nodelist, force = True)
    elif mode == MODE_CLEAN:
        clean(nodelist)
    else:
        raise ValueError("Invalid mode %r" % (mode,))


























